package com.xiyuan.smartutils.xml;

import com.xiyuan.smartutils.Asserts;
import com.xiyuan.smartutils.Types;
import com.xiyuan.smartutils.constants.CodeConstants;
import com.xiyuan.smartutils.constants.SignConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * Xml定义类
 *
 * @version v1.1.2 @author lgz 2017-8-21 新建与整理
 */
public class Xml implements SignConstants, CodeConstants
{
    public static final Xml xml = new Xml();
    
    private boolean versionFlag = true;//默认输出<?xml version="1.0" encoding="UTF-8"?>
    private String version = "1.0";
    private String encoding = "UTF-8";
    private boolean format = true;
    
    private XmlFactory factory;
    
    public Xml()
    {
        factory = new XmlFactory(this);
    }
    
    public String getXmlVersionTag()
    {
        return new StringBuilder("<?xml version=\"").append(version).append("\" encoding=\"").append(encoding).append("\"?>").toString();
    }
    
    /**
     * 对象转换成XML字符串
     * 
     * @param obj   对象
     * @return      JSON字符串
     */
    public String toString(Object obj)
    {
        if (obj == null)
        {//XML不支持null，统一返回空字符串
            return _EMPTY_;
        }
        
        if (Types.isSimpleType(obj))
        {//单一类型，返回String.valueOf
            return String.valueOf(obj);
        }
        
        StringBuilder strb = new StringBuilder();
        if (versionFlag)
        {//要求版本标志并且不是单一类型时有效
            strb.append(getXmlVersionTag());
        }
        
        String tagName = null;
        if (obj instanceof XmlTag)
        {//如果对象实现XmlTag接口则读出来
            tagName = ((XmlTag)obj).getXmlTag();
        }
        
        //到解释工厂中找到解释器解释
        strb.append(toStringInner(obj, tagName, 0));
        return strb.toString();
    }
    
    /** 从解释工厂中找到解释器解释 */
    public String toStringInner(Object obj, String tagName, int tagLevel)
    {
        return (factory.getParser(obj.getClass())).toStringInner(obj, tagName, tagLevel);
    }
    
    /**
     * XML字符串转换成对象
     * 
     * @param xml  XML字符串
     * @param clazz 转换成对象的类
     * @return      obj对象
     */
    public <T> T toObject(String xml, Class<T> clazz)
    {
        Asserts.as(xml != null ? null : "XML转对象时，XML不允许为null");
        
        try
        {
            Document doc = Xmls.buildDocument(xml, _UTF_8_);
            Node node = doc.getFirstChild();
            return toObjectInner(node, clazz, null);
        }
        catch (Exception e)
        {
            throw Asserts.exception("XML转对象时，XML格式不正确:"+e.getMessage());
        }
    }
    
    /**
     * XML字符串转换成对象
     * 
     * @param node  XML节点
     * @param clazz 转换成对象的类
     * @return      obj对象
     */
    @SuppressWarnings("unchecked")
    public <T> T toObjectInner(Node node, Class<T> clazz, Class<?> generics)
    {
        return (T)factory.getParser(clazz).toObjectInner(node, clazz, generics);
    }
    
    public boolean isFormat()
    {
        return format;
    }
}
